Allow using opt-level="s"/"z" in profile overrides.
authorwhitequark <whitequark@whitequark.org>
Wed, 17 Aug 2016 07:35:57 +0000 (07:35 +0000)
committerwhitequark <whitequark@whitequark.org>
Wed, 17 Aug 2016 22:14:09 +0000 (22:14 +0000)
Fixes #2655.

src/cargo/core/manifest.rs
src/cargo/ops/cargo_rustc/custom_build.rs
src/cargo/ops/cargo_rustc/job_queue.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/util/toml.rs
tests/profiles.rs

index 02e9b4527df651237cdcd38e8e05fad49c6a9b64..a0e7450574f1eda103914550ac92cc3ec2d02f4b 100644 (file)
@@ -121,7 +121,7 @@ impl Encodable for TargetKind {
 
 #[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Profile {
-    pub opt_level: u32,
+    pub opt_level: String,
     pub lto: bool,
     pub codegen_units: Option<u32>,    // None = use rustc default
     pub rustc_args: Option<Vec<String>>,
@@ -473,7 +473,7 @@ impl Profile {
 
     pub fn default_release() -> Profile {
         Profile {
-            opt_level: 3,
+            opt_level: "3".to_string(),
             debuginfo: false,
             ..Profile::default()
         }
@@ -511,7 +511,7 @@ impl Profile {
 impl Default for Profile {
     fn default() -> Profile {
         Profile {
-            opt_level: 0,
+            opt_level: "0".to_string(),
             lto: false,
             codegen_units: None,
             rustc_args: None,
index e2ea45226285795479a882a338a487f7807c54ed..ffc1aeaab8f15b75f97bc79f96b8bb97058477c2 100644 (file)
@@ -111,7 +111,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
          Kind::Target => cx.target_triple(),
      })
      .env("DEBUG", &profile.debuginfo.to_string())
-     .env("OPT_LEVEL", &profile.opt_level.to_string())
+     .env("OPT_LEVEL", &profile.opt_level)
      .env("PROFILE", if cx.build_config.release {"release"} else {"debug"})
      .env("HOST", cx.host_triple())
      .env("RUSTC", &try!(cx.config.rustc()).path)
index 103e87cc4e9305ec67b289eb9531a8933d322e9a..92d72135a2f4120915e15b7b0f9e7c2707100a54 100644 (file)
@@ -200,8 +200,8 @@ impl<'a> JobQueue<'a> {
 
         let build_type = if self.is_release { "release" } else { "debug" };
         let profile = cx.lib_profile(cx.resolve.root());
-        let mut opt_type = String::from(if profile.opt_level > 0 { "optimized" }
-                                        else { "unoptimized" });
+        let mut opt_type = String::from(if profile.opt_level == "0" { "unoptimized" }
+                                        else { "optimized" });
         if profile.debuginfo {
             opt_type = opt_type + " + debuginfo";
         }
index 27719613905c772953ad644a12ed2968b116d17f..f0811e03c00cf5856d68f7c53b3ce22e1cd22c38 100644 (file)
@@ -477,7 +477,7 @@ fn build_base_args(cx: &Context,
                    unit: &Unit,
                    crate_types: &[&str]) {
     let Profile {
-        opt_level, lto, codegen_units, ref rustc_args, debuginfo,
+        ref opt_level, lto, codegen_units, ref rustc_args, debuginfo,
         debug_assertions, rpath, test, doc: _doc, run_custom_build,
         ref panic, rustdoc_args: _,
     } = *unit.profile;
@@ -509,7 +509,7 @@ fn build_base_args(cx: &Context,
         cmd.arg("-C").arg("prefer-dynamic");
     }
 
-    if opt_level != 0 {
+    if opt_level != "0" {
         cmd.arg("-C").arg(&format!("opt-level={}", opt_level));
     }
 
@@ -549,9 +549,9 @@ fn build_base_args(cx: &Context,
         cmd.args(args);
     }
 
-    if debug_assertions && opt_level > 0 {
+    if debug_assertions && opt_level != "0" {
         cmd.args(&["-C", "debug-assertions=on"]);
-    } else if !debug_assertions && opt_level == 0 {
+    } else if !debug_assertions && opt_level == "0" {
         cmd.args(&["-C", "debug-assertions=off"]);
     }
 
index 7b805d51b837b4abbfb9fdd7fe722af27c713011..0c138e648bf059758854a0746d58743f92d3daad 100644 (file)
@@ -256,9 +256,28 @@ pub struct TomlProfiles {
     release: Option<TomlProfile>,
 }
 
+#[derive(Clone)]
+pub struct TomlOptLevel(String);
+
+impl Decodable for TomlOptLevel {
+    fn decode<D: Decoder>(d: &mut D) -> Result<TomlOptLevel, D::Error> {
+        match d.read_u32() {
+            Ok(i) => Ok(TomlOptLevel(i.to_string())),
+            Err(_) => {
+                match d.read_str() {
+                    Ok(ref s) if s == "s" || s == "z" =>
+                        Ok(TomlOptLevel(s.to_string())),
+                    Ok(_) | Err(_) =>
+                        Err(d.error("expected an integer, a string \"z\" or a string \"s\""))
+                }
+            }
+        }
+    }
+}
+
 #[derive(RustcDecodable, Clone, Default)]
 pub struct TomlProfile {
-    opt_level: Option<u32>,
+    opt_level: Option<TomlOptLevel>,
     lto: Option<bool>,
     codegen_units: Option<u32>,
     debug: Option<bool>,
@@ -1188,14 +1207,14 @@ fn build_profiles(profiles: &Option<TomlProfiles>) -> Profiles {
 
     fn merge(profile: Profile, toml: Option<&TomlProfile>) -> Profile {
         let &TomlProfile {
-            opt_level, lto, codegen_units, debug, debug_assertions, rpath,
+            ref opt_level, lto, codegen_units, debug, debug_assertions, rpath,
             ref panic
         } = match toml {
             Some(toml) => toml,
             None => return profile,
         };
         Profile {
-            opt_level: opt_level.unwrap_or(profile.opt_level),
+            opt_level: opt_level.clone().unwrap_or(TomlOptLevel(profile.opt_level)).0,
             lto: lto.unwrap_or(profile.lto),
             codegen_units: codegen_units,
             rustc_args: None,
index 3b86a7672b9286bf473fb864c8ddb7a943cc62cd..ab060bba265ece822cb60408467a59ec77a15a17 100644 (file)
@@ -4,6 +4,7 @@ extern crate hamcrest;
 use std::env;
 use std::path::MAIN_SEPARATOR as SEP;
 
+use cargotest::is_nightly;
 use cargotest::support::{project, execs};
 use hamcrest::assert_that;
 
@@ -42,6 +43,85 @@ url = p.url(),
 )));
 }
 
+#[test]
+fn opt_level_override_0() {
+    let mut p = project("foo");
+    p = p
+        .file("Cargo.toml", r#"
+            [package]
+
+            name = "test"
+            version = "0.0.0"
+            authors = []
+
+            [profile.dev]
+            opt-level = 0
+        "#)
+        .file("src/lib.rs", "");
+    assert_that(p.cargo_process("build").arg("-v"),
+                execs().with_status(0).with_stderr(&format!("\
+[COMPILING] test v0.0.0 ({url})
+[RUNNING] `rustc src{sep}lib.rs --crate-name test --crate-type lib \
+        -g \
+        -C metadata=[..] \
+        --out-dir [..] \
+        --emit=dep-info,link \
+        -L dependency={dir}{sep}target{sep}debug{sep}deps`
+[FINISHED] [..] target(s) in [..]
+", sep = SEP,
+dir = p.root().display(),
+url = p.url()
+)));
+}
+
+fn check_opt_level_override(profile_level: &str, rustc_level: &str) {
+    let mut p = project("foo");
+    p = p
+        .file("Cargo.toml", &format!(r#"
+            [package]
+
+            name = "test"
+            version = "0.0.0"
+            authors = []
+
+            [profile.dev]
+            opt-level = {level}
+        "#, level = profile_level))
+        .file("src/lib.rs", "");
+    assert_that(p.cargo_process("build").arg("-v"),
+                execs().with_status(0).with_stderr(&format!("\
+[COMPILING] test v0.0.0 ({url})
+[RUNNING] `rustc src{sep}lib.rs --crate-name test --crate-type lib \
+        -C opt-level={level} \
+        -g \
+        -C debug-assertions=on \
+        -C metadata=[..] \
+        --out-dir [..] \
+        --emit=dep-info,link \
+        -L dependency={dir}{sep}target{sep}debug{sep}deps`
+[FINISHED] [..] target(s) in [..]
+", sep = SEP,
+dir = p.root().display(),
+url = p.url(),
+level = rustc_level
+)));
+}
+
+#[test]
+fn opt_level_overrides() {
+    if !is_nightly() { return }
+
+    for &(profile_level, rustc_level) in &[
+        ("1", "1"),
+        ("2", "2"),
+        ("3", "3"),
+        ("\"s\"", "s"),
+        ("\"z\"", "z"),
+    ] {
+        check_opt_level_override(profile_level, rustc_level)
+    }
+}
+
 #[test]
 fn top_level_overrides_deps() {
     let mut p = project("foo");